/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "st7789.h"
#include "cst816d.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define STM32_CS_PORT   GPIOB
#define STM32_CS_PIN    GPIO_PIN_0
#define STM32_RST_PORT  GPIOB
#define STM32_RST_PIN   GPIO_PIN_1
#define STM32_DC_PORT   GPIOB
#define STM32_DC_PIN    GPIO_PIN_2
#define STM32_BL_PORT   GPIOB
#define STM32_BL_PIN    GPIO_PIN_10

#define STM32_INT_PORT  GPIOB
#define STM32_INT_PIN   GPIO_PIN_5
#define STM32_RES_PORT  GPIOB
#define STM32_RES_PIN   GPIO_PIN_4
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;

SPI_HandleTypeDef hspi1;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
typedef struct point {
	int x;
	int y;
} point_t;

typedef struct rect {
	int x;
	int y;
	int w;
	int h;
} rect_t;

/* 矩形框 */
static int g_fill_flag[3][3] = {{0 ,0 ,0}, {0 ,0 ,0}, {0 ,0 ,0}};
static rect_t g_rect[3][3] =
{
	[0] =
	{
		[0] =
		{
			.x = 20,
			.y = 20,
			.w = 40,
			.h = 40,
		},
		[1] =
		{
			.x = 100,
			.y = 20,
			.w = 40,
			.h = 40,
		},
		[2] =
		{
			.x = 180,
			.y = 20,
			.w = 40,
			.h = 40,
		},
	},
	[1] =
	{
		[0] =
		{
			.x = 20,
			.y = 120,
			.w = 40,
			.h = 40,
		},
		[1] =
		{
			.x = 100,
			.y = 120,
			.w = 40,
			.h = 40,
		},
		[2] =
		{
			.x = 180,
			.y = 120,
			.w = 40,
			.h = 40,
		},
	},
	[2] =
	{
		[0] =
		{
			.x = 20,
			.y = 220,
			.w = 40,
			.h = 40,
		},
		[1] =
		{
			.x = 100,
			.y = 220,
			.w = 40,
			.h = 40,
		},
		[2] =
		{
			.x = 180,
			.y = 220,
			.w = 40,
			.h = 40,
		},
	},
};

struct st7789 lcd;
struct cst816d tp;
bool flag = 0;

void lcd_draw_rect(rect_t *rect, uint16_t color)
{
	point_t p_up_left;
	point_t p_up_rigth;
	point_t p_down_left;
	point_t p_down_rigth;

	p_up_left.x = rect->x;
	p_up_left.y = rect->y;

	p_up_rigth.x = rect->x + rect->w - 1;
	p_up_rigth.y = rect->y;

	p_down_left.x = rect->x;
	p_down_left.y = rect->y + rect->h - 1;

	p_down_rigth.x = rect->x + rect->w - 1;
	p_down_rigth.y = rect->y + rect->h - 1;

	// 矩形上面的横线
	st7789_rect_fill_color(&lcd, p_up_left.x, p_up_left.y, p_up_rigth.x, p_up_rigth.y, color);

	// 矩形下面的横线
	st7789_rect_fill_color(&lcd, p_down_left.x, p_down_left.y, p_down_rigth.x, p_down_rigth.y, color);

	// 矩形左边的竖线
	st7789_rect_fill_color(&lcd, p_up_left.x, p_up_left.y, p_down_left.x, p_down_left.y, color);

	// 矩形右边的竖线
	st7789_rect_fill_color(&lcd, p_up_rigth.x, p_up_rigth.y, p_down_rigth.x, p_down_rigth.y, color);
}

static void stm32_rst_pin(int val)
{
	HAL_GPIO_WritePin(STM32_RST_PORT, STM32_RST_PIN, val);
}

static void stm32_dc_pin(int val)
{
	HAL_GPIO_WritePin(STM32_DC_PORT, STM32_DC_PIN, val);
}

static void stm32_bl_pin(int val)
{
	HAL_GPIO_WritePin(STM32_BL_PORT, STM32_BL_PIN, val);
}

static void stm32_cs_pin(int val)
{
	HAL_GPIO_WritePin(STM32_CS_PORT, STM32_CS_PIN, val);
}

static void stm32_spi_write(uint8_t* bytes, uint32_t len)
{
	uint32_t section = 4096;

	if (!len) {
		return;
	}

	stm32_cs_pin(GPIO_PIN_RESET);
	while (len > section) {
		HAL_SPI_Transmit(&hspi1, bytes, section, 1000);
		bytes += section;
		len -= section;
	}

	HAL_SPI_Transmit(&hspi1, bytes, len, 1000);
	stm32_cs_pin(GPIO_PIN_SET);
}

static void stm32_res_pin(int val)
{
	HAL_GPIO_WritePin(STM32_RST_PORT, STM32_RES_PIN, val);
}

static int stm32_i2c_read(uint8_t reg, uint8_t* bytes, uint32_t len)
{
	return HAL_I2C_Mem_Read(&hi2c1, (CST816D_I2C_7BIT_ADDR << 1) + 1, reg, I2C_MEMADD_SIZE_8BIT, bytes, len, 1000);
}

static int stm32_i2c_write(uint8_t reg, uint8_t* bytes, uint32_t len)
{
	return HAL_I2C_Mem_Write(&hi2c1, CST816D_I2C_7BIT_ADDR << 1, reg, I2C_MEMADD_SIZE_8BIT, bytes, len, 1000);
}

static void stm32_msleep(int ms)
{
	HAL_Delay(ms);
}

static void board_init()
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_GPIOH_CLK_ENABLE();

	/* LCD */
	GPIO_InitStruct.Pin = STM32_CS_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(STM32_CS_PORT, &GPIO_InitStruct);
	HAL_GPIO_WritePin(STM32_CS_PORT, STM32_CS_PIN, GPIO_PIN_RESET);

	GPIO_InitStruct.Pin = STM32_RST_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(STM32_RST_PORT, &GPIO_InitStruct);
	HAL_GPIO_WritePin(STM32_RST_PORT, STM32_RST_PIN, GPIO_PIN_RESET);

	GPIO_InitStruct.Pin = STM32_DC_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(STM32_DC_PORT, &GPIO_InitStruct);
	HAL_GPIO_WritePin(STM32_DC_PORT, STM32_DC_PIN, GPIO_PIN_RESET);

	GPIO_InitStruct.Pin = STM32_BL_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(STM32_BL_PORT, &GPIO_InitStruct);
	HAL_GPIO_WritePin(STM32_BL_PORT, STM32_BL_PIN, GPIO_PIN_RESET);

	/* TP */
	GPIO_InitStruct.Pin = STM32_RES_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(STM32_RES_PORT, &GPIO_InitStruct);
	HAL_GPIO_WritePin(STM32_RES_PORT, STM32_RES_PIN, GPIO_PIN_RESET);

	GPIO_InitStruct.Pin = STM32_INT_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(STM32_INT_PORT, &GPIO_InitStruct);

	HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

	/* LED */
	GPIO_InitStruct.Pin = GPIO_PIN_13;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  int i = 0;
  int j = 0;
  int ret = 0;
  int sum = 0;
  int dot = 1;
  bool pressed = 0;
  uint16_t x = 0;
  uint16_t y = 0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  board_init();

  lcd.cfg.fix.width = 240;
  lcd.cfg.fix.height = 280;
  lcd.cfg.fix.xshift = 0;
  lcd.cfg.fix.yshift = 20;
  lcd.cfg.fix.bits = 8;
  lcd.cfg.var.orien = ROTATE_0;
  lcd.ops.reset = stm32_rst_pin;
  lcd.ops.datacmd = stm32_dc_pin;
  lcd.ops.backlight = stm32_bl_pin;
  lcd.ops.msleep = stm32_msleep;
  lcd.ops.write = stm32_spi_write;
  st7789_init(&lcd);

  tp.cfg.fix.width = 240;
  tp.cfg.fix.height = 280;
  tp.ops.read = stm32_i2c_read;
  tp.ops.write = stm32_i2c_write;
  tp.ops.msleep = stm32_msleep;
  tp.ops.reset = stm32_res_pin;
  cst816d_init(&tp);

  /* white background */
  st7789_rect_fill_color(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, RGB565_WHITE);

  for(i = 0; i < 3; i++)
  {
    for(j = 0; j < 3; j++)
    {
      lcd_draw_rect(&g_rect[i][j], RGB565_BLACK);
    }
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    if (flag) {
      ret = cst816d_get_coord(&tp, &pressed, &x, &y);
      if (0 == ret) {
        rect_t* r = NULL;
        st7789_rect_fill_color(&lcd, x, y, x + dot, y + dot, RGB565_RED);
        sum = 0;
        for (i = 0; i < 3; i++) {
          for (j = 0; j < 3; j++) {
            r = &g_rect[i][j];
            if ((x > r->x) && (x < r->x + r->w) && (y > r->y) && (y < r->y + r->h) && (0 == g_fill_flag[i][j])) {
              g_fill_flag[i][j] = 1;
              st7789_rect_fill_color(&lcd, r->x, r->y, r->x + r->w - 1, r->y + r->h - 1, RGB565_RED);
              st7789_rect_fill_color(&lcd, x, y, x + dot, y + dot, RGB565_BLACK);
            } else {
              st7789_rect_fill_color(&lcd, x, y, x + dot, y + dot, RGB565_BLACK);
            }
            sum = sum + g_fill_flag[i][j];
          }
        }

        if (9 == sum) {
          break;
        }
      }
      flag = 0;
    } else {
      HAL_Delay(10);
    }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

  HAL_Delay(500);
  lcd.ops.backlight(0);
  HAL_Delay(500);
  lcd.ops.backlight(1);

  lv_init();
  lv_port_disp_init();
  lv_port_indev_init();

  HAL_Delay(500);
  lcd.ops.backlight(0);
  HAL_Delay(500);
  lcd.ops.backlight(1);

  extern void lv_example_btnmatrix_3(void);
  extern void lv_example_keyboard_1(void);
  lv_example_keyboard_1();

  while (1) {
    lv_tick_inc(10);
    lv_timer_handler();
    HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }

  /** Enables the Clock Security System
  */
  HAL_RCC_EnableCSS();
}

/**
  * @brief I2C1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}

/* USER CODE BEGIN 4 */
int __io_putchar(int ch)
{
  HAL_UART_Transmit(&huart1, (uint8_t *) &ch, 1, HAL_MAX_DELAY);
  return (ch);
}

void EXTI9_5_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI9_5_IRQn 0 */

  /* USER CODE END EXTI9_5_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
  /* USER CODE BEGIN EXTI9_5_IRQn 1 */

  /* USER CODE END EXTI9_5_IRQn 1 */
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  flag = 1;
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
